--- 2.6.24.3.base/fs/bio.c	2008-03-16 03:46:00.000000000 -0700
+++ 2.6.24.3/fs/bio.c	2008-03-16 03:44:03.000000000 -0700
@@ -31,6 +31,63 @@
 #define BIO_POOL_SIZE 2
 #define BIO_NR_POOLS 6
 
+/* Bio push/pop (C) 2008, Daniel Phillips <phillips@phunq.net> */
+
+#define BIOSTACK_ALIGN (1 << 2)
+#define BIOCHUNK_SIZE (1 << 7)
+#define BIOCHUNK_MAGIC (0xddc0ffee)
+#define BIOCHUNK_OVERHEAD (sizeof(struct biochunk) + sizeof(struct bioframe))
+#define BIOCHUNK_PAYLOAD (BIOCHUNK_SIZE - BIOCHUNK_OVERHEAD)
+
+struct biochunk { u32 magic; void *oldstack; char frames[]; };
+
+static struct kmem_cache *biospace __read_mostly;
+
+static struct biochunk *alloc_biochunk(void)
+{
+	return kmem_cache_alloc(biospace, __GFP_NOFAIL);
+}
+
+static void free_biochunk(struct biochunk *chunk)
+{
+	kmem_cache_free(biospace, chunk);
+}
+
+void *bio_push(struct bio *bio, unsigned size, bio_end_io_t *endio)
+{
+	struct bioframe *frame = bio->bi_stack;
+	size += sizeof(struct bioframe);
+	size += -size & (BIOSTACK_ALIGN - 1);
+	if (unlikely(size > frame->stacksize)) {
+		struct biochunk *chunk = alloc_biochunk();
+		bio_end_io_t *old = frame->endio;
+		BUG_ON(size > BIOCHUNK_PAYLOAD);
+		*chunk = (struct biochunk){ .oldstack = bio->bi_stack, .magic = BIOCHUNK_MAGIC };
+		frame = bio->bi_stack = chunk->frames;
+		*frame = (struct bioframe){ .stacksize = BIOCHUNK_PAYLOAD, .endio = old };
+	}
+	bio->bi_stack += size;
+	*(struct bioframe *)bio->bi_stack = (struct bioframe){
+		.stacksize = frame->stacksize - size,
+		.framesize = size, .endio = endio };
+	return frame->space;
+}
+EXPORT_SYMBOL_GPL(bio_push);
+
+void *bio_pop(struct bio *bio)
+{
+	struct bioframe *frame = bio->bi_stack;
+	if (unlikely(!frame->framesize)) {
+		struct biochunk *chunk = bio->bi_stack - sizeof(struct biochunk);
+		BUG_ON(chunk->magic != BIOCHUNK_MAGIC);
+		frame = bio->bi_stack = chunk->oldstack;
+		free_biochunk(chunk);
+	}
+	frame = bio->bi_stack -= frame->framesize;
+	return frame->space;
+}
+EXPORT_SYMBOL_GPL(bio_pop);
+
 /*
  * a small number of entries is fine, not going to be performance critical.
  * basically we just need to survive
@@ -76,6 +133,8 @@ void bio_free(struct bio *bio, struct bi
 	const int pool_idx = BIO_POOL_IDX(bio);
 	BIO_BUG_ON(pool_idx >= BIO_NR_POOLS);
 	BIO_BUG_ON(!bio->bi_io_vec);
+	if (!((struct bioframe *)bio->bi_stack)->framesize)
+		bio_pop(bio);
 	mempool_free(bio, bio_set->bio_pools[pool_idx]);
 }
 
@@ -130,6 +189,8 @@ struct bio *bio_alloc_bioset(gfp_t gfp_m
 	bio->bi_flags |= idx << BIO_POOL_OFFSET;
 	bio->bi_max_vecs = bio_slabs[idx].nr_vecs;
 	bio->bi_io_vec = (void *)bio + sizeof(struct bio);
+	bio->bi_stack = &bio->space;
+	bio->space.framesize = sizeof(struct bioframe);
 	return bio;
 }
 
@@ -1102,6 +1163,8 @@ static int __init init_bio(void)
 	if (!bio_split_pool)
 		panic("bio: can't create split pool\n");
 
+	biospace = kmem_cache_create("biospace", BIOCHUNK_SIZE, 0, SLAB_PANIC, NULL);
+
 	return 0;
 }
 
--- 2.6.24.3.base/include/linux/bio.h	2008-03-16 03:46:00.000000000 -0700
+++ 2.6.24.3/include/linux/bio.h	2008-03-16 03:44:51.000000000 -0700
@@ -68,6 +68,11 @@ typedef void (bio_end_io_t) (struct bio 
 typedef void (bio_destructor_t) (struct bio *);
 
 /*
+ * Support endio handler stacking with per-handler private workspace
+ */
+struct bioframe { u16 framesize, stacksize; bio_end_io_t *endio; char space[]; };
+
+/*
  * main unit of I/O for the block layer and lower layers (ie drivers and
  * stacking drivers)
  */
@@ -114,6 +119,8 @@ struct bio {
 	void			*bi_private;
 
 	bio_destructor_t	*bi_destructor;	/* destructor */
+	void			*bi_stack;	/* endio stacking */
+	struct bioframe		space;
 };
 
 /*
@@ -201,12 +208,12 @@ static inline void *bio_data(struct bio 
 
 static inline void bio_set_endio(struct bio *bio, bio_end_io_t *endio)
 {
-	bio->bi_endio = endio;
+	((struct bioframe *)bio->bi_stack)->endio = endio;
 }
 
 static inline bio_end_io_t *bio_get_endio(struct bio *bio)
 {
-	return bio->bi_endio;
+	return ((struct bioframe *)bio->bi_stack)->endio;
 }
 
 /*
@@ -310,7 +317,8 @@ extern struct bio *bio_alloc(gfp_t, int)
 extern struct bio *bio_alloc_bioset(gfp_t, int, struct bio_set *);
 extern void bio_put(struct bio *);
 extern void bio_free(struct bio *, struct bio_set *);
-
+extern void *bio_push(struct bio *bio, unsigned size, bio_end_io_t *endio);
+extern void *bio_pop(struct bio *bio);
 extern void bio_endio(struct bio *, int);
 struct request_queue;
 extern int bio_phys_segments(struct request_queue *, struct bio *);
